#!/usr/bin/env python

#
# AUTHOR: Robert Wikman <rbw@vault13.org>
# DATE: 2011-07-25
# License: GPL
#

import urllib
import getopt
import sys, os
from xml.dom import minidom

URL = "http://www.google.com/ig/api?stock="
CONFIG = ".conkyStocks.config"

def usage():
    sys.stdout.write('''
    --- Conky stocks tool ---
    Fast and robust plugin for Conky that uses the Google finance API for gathering and parsing stock quote data.
    Author: Robert Wikman <rbw@vault13.org>
    License: GPL
    
    Usage:
    ./conkyStocks.py <COMMAND>
    
        Commands (mutually exclusive):
            -s, --symbols <symbols(s)>    Comma separated list of stock symbols
            -k, --keys                    Lists available keys
    
    Examples:
    ./conkyStocks.py --symbols goog,rht,intc
    ./conkyStocks.py --keys

''')

class StocksError(Exception):    
    def __init__(self, message, code):
        self.code = code
        self.message = message
                        
    def __str__(self):
        return repr(self.message) 
    
class Stocks:
    def __init__(self, symbols):
        url_args = '&stock='.join(symbols.split(','))
        url = URL + url_args
        dom = minidom.parse(urllib.urlopen(url))
        self.elements = dom.getElementsByTagName('finance')

    def getKeys(self):
        return dict([(element.nodeName, str(element.attributes['data'].value)) for element in self.elements[0].childNodes])

    def getStockData(self):
        retval = []
        for element in self.elements:
            data = dict([(element.nodeName, str(element.attributes['data'].value)) for element in element.childNodes])
            if not data['company']:
                retval.append("%s - Error: No such symbol" % data['symbol'])
                continue
            
            try:
                if float(data['perc_change']) > 0: color = "${color %s}" % COLOR_STOCK_UP  
                elif float(data['perc_change']) == 0: color = "${color}" 
                else: color = "${color %s}" % COLOR_STOCK_DOWN
            except ValueError:
                retval.append("%s - Error: Couldn't parse data" % data['symbol'])
                continue
            
            data['perc_change'] = "%s %s%% ${color}" % (color, str(data['perc_change']))
            
            try:
                retval.append(eval(OUTPUT_ROW))
            except SyntaxError, err:
                raise StocksError(err,1001)
            except KeyError, err:
                raise StocksError(err,1002)            
                            
        return retval

def main():
    def checkExclusive(flag):
        if (flag == True):
            raise getopt.GetoptError('Multiple mutually exclusive commands not allowed')
    
        return True    
    
    symbols = None
    get_keys = None
    exclusive = False
    
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hks:", ["help", 
                                                          "symbols=", 
                                                          "keys"])

        for opt,arg in opts:
            if opt in ('-s', '--symbols'):
                exclusive = checkExclusive(exclusive)
                symbols = arg
                
            elif opt in ('-k', '--keys'):
                exclusive = checkExclusive(exclusive)
                get_keys = 1
                symbols = 'goog'
                                                                     
            elif opt in ('-h', '--help'):                
                usage()
                exit(0)   
        
        
        if (symbols or get_keys) is None:
            raise getopt.GetoptError('Too few arguments')
        
        else:
            try:
                s = Stocks(symbols)

                if get_keys:
                    keys_data = s.getKeys()
                    sys.stdout.write("\n== Keys / Values (symbol 'GOOG') ==\n\n")
                    for row in keys_data:
                        sys.stdout.write("key: '%s', output: '%s'\n" % (row, keys_data[row]))
                    
                    sys.stdout.write("\n")
                    
                elif symbols == arg:
                    for row in s.getStockData():
                        sys.stdout.write(row + "\n")
            
            except StocksError, err:
                sys.stdout.write("\n === ERROR === \n")
                if err.code == 1001:
                    message, info = err.message
                    sys.stdout.write("Configuration couldn't be parsed due to a syntax error.\n")
                    sys.stdout.write("Character: %s" % str(info[2]))
                    sys.stdout.write("\nConfig: \n %s" % str(info[3]))
                    sys.stdout.write("\nmessage: %s \n\n" % str(message))
                elif err.code == 1002:
                    sys.stdout.write("Configuration couldn't be parsed due to invalid key usage.\n")
                    sys.stdout.write("key: %s \n\n" % str(err.message))                   
                else:
                    sys.stdout.write(err.message + "\n\n")
                    
                sys.exit(1)    
            
            except IOError, err:
                sys.stdout.write(str(err) + "\n\n")
                sys.exit(1)           

    except getopt.GetoptError, err:        
        usage()
        sys.stdout.write("    - ERROR: %s \n\n" % str(err)) 
        sys.exit(2)



if __name__ == "__main__":   
    try:
        f = open(os.path.join(os.path.expanduser('~'), CONFIG), 'r')
        exec(f)
    except IOError, err:
        sys.stdout.write(str(err) + "\n")
        sys.exit(1)
    else:
        f.close()
        
    main()


    
    